package cn.asiontang.utils;

import android.annotation.SuppressLint;
import android.app.Application;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 同样的原理，可以写出“永不消逝的Toast”！Handler间隔N秒自动调用toast.show();<br/>
 * 即可 全局统一的Toast。每次显示都只有一个Toast对象。<br/>
 * 方便在状态更新频繁的Toast信息显示代码中，提供实时刷新显示功能。<br/>
 * 如：同步过程的状态更新等等。<br/>
 * 【线程安全的。支持从任意非主线程调用。】
 *
 * <pre>
 * 【必须先调用{@link #init(Application)} 初始化，方能全局使用】
 * </pre>
 *
 * @author AsionTang
 * @version 1.5
 * @since 1.0（2013年05月22日）：首个原型<br/>
 * 1.1（2013年10月22日）：将统一使用全局的Application来显示Toast。<br/>
 * 1.2（2013年11月27日）：修复了非主线程增相调用异常的问题。实现了线程安全，可从任意线程调用显示。
 * 1.3（2014年06月30日）：添加了ToastEx.makeTextAndShowLong[Short]系列函数简便Toast的调用。
 * 1.4（2015年??月??日）：添加了ToastEx.showAndWait[Short]系列函数以便在显示完Toast之后才执行之后代码
 * 1.5（2015年10月21日）：完善了参数，使得所有Toast支持CharSequence参数，以便显示多格式问题
 */
public class ToastEx
{
    private static Toast mToast;
    /**
     * 记住通过makeText的方式最后显示的Toast对象，以便在需要Hide时，尽可能成功的Hide掉。
     */
    private static Toast mMakedToast;
    private static Application mContext;
    private static ToastHandler mHandler;

    public static final void hide()
    {
        if (mMakedToast != null)
            mMakedToast.cancel();
        if (mToast != null)
            mToast.cancel();
    }

    /**
     * 一般在自定义Application中的onCreate里初始化<br/>
     * 【不能在Application的构造函数里调用！】<br/>
     * 因为此时应用的String资源尚未初始化完毕，会报Null异常！
     */
    @SuppressLint("ShowToast")
    public static void init(final Application app)
    {
        mContext = app;

        //防止第一遍在非主线程里调用！会出现以下异常：
        //RuntimeException: Can't create handler inside thread that has not called Looper.prepare
        mToast = Toast.makeText(mContext, android.R.string.ok, Toast.LENGTH_SHORT);
    }

    private synchronized static void makeTextAndShow(final Object text, final int duration)
    {
        //修复了：CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.异常
        if (Looper.myLooper() != Looper.getMainLooper())
        {
            if (mHandler == null)
                mHandler = new ToastHandler(mToast);
            final Message msg = mHandler.obtainMessage();
            msg.what = ToastHandler.MAKE_TOAST;
            msg.arg1 = duration;
            msg.obj = text;
            msg.sendToTarget();
        }
        else
        {
            if (text instanceof CharSequence)
                mMakedToast = Toast.makeText(mContext, (CharSequence) text, duration);
            else
                mMakedToast = Toast.makeText(mContext, String.valueOf(text), duration);
            mMakedToast.show();
        }
    }

    public static final void makeTextAndShowLong(final CharSequence text)
    {
        makeTextAndShow(text, Toast.LENGTH_LONG);
    }

    public static final void makeTextAndShowLong(final int resId)
    {
        makeTextAndShow(mContext.getText(resId), Toast.LENGTH_LONG);
    }

    public static final void makeTextAndShowLong(final Object text)
    {
        makeTextAndShow(text, Toast.LENGTH_LONG);
    }

    public static final void makeTextAndShowShort(final CharSequence text)
    {
        makeTextAndShow(text, Toast.LENGTH_SHORT);
    }

    public static final void makeTextAndShowShort(final int resId)
    {
        makeTextAndShow(mContext.getText(resId), Toast.LENGTH_SHORT);
    }

    public static final void makeTextAndShowShort(final Object text)
    {
        makeTextAndShow(text, Toast.LENGTH_SHORT);
    }

    public static final void show(final CharSequence text)
    {
        show(text, Toast.LENGTH_SHORT);
    }

    private synchronized static final void show(final Object text, final int duration)
    {
        //修复了：CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.异常
        if (Looper.myLooper() != Looper.getMainLooper())
        {
            if (mHandler == null)
                mHandler = new ToastHandler(mToast);
            final Message msg = mHandler.obtainMessage();
            msg.what = ToastHandler.ONE_TOAST;
            msg.arg1 = duration;
            msg.obj = text;
            msg.sendToTarget();
        }
        else
        {
            mToast.setDuration(duration);

            ViewGroup group = (ViewGroup) mToast.getView();
            group.setBackgroundColor(Color.WHITE);

            TextView textView = (TextView) group.getChildAt(0);
            textView.setTextColor(Color.BLACK);
            textView.setTextSize(16);

            if (text instanceof CharSequence)
                mToast.setText((CharSequence) text);
            else
                mToast.setText(String.valueOf(text));
            mToast.show();
        }
    }

    public static final void show(final int resId)
    {
        show(mContext.getText(resId), Toast.LENGTH_SHORT);
    }

    public static final void show(final Object text)
    {
        show(text, Toast.LENGTH_SHORT);
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWait(final CharSequence text)
    {
        showAndWait(text, Toast.LENGTH_SHORT);
    }

    /**
     * 异步显示Toast，并阻塞当前进程指定时间
     *
     * @param duration <ul>
     *                 <li>Toast.LENGTH_SHORT：阻塞2000毫秒</li>
     *                 <li>
     *                 Toast.LENGTH_LONG：阻塞3500毫秒</li>
     *                 <li>其它值：阻塞duration【毫秒】</li>
     *                 </ul>
     */
    public synchronized static final void showAndWait(final Object text, final int duration)
    {
        //先把可能的已经显示的ToastEx隐藏！尽可能的加快下面的Toast的显示。
        hide();

        //使用Toast来显示异常信息
        final Thread t = new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    Looper.prepare();

                    if (text instanceof CharSequence)
                        Toast.makeText(mContext, (CharSequence) text, duration).show();
                    else
                        Toast.makeText(mContext, String.valueOf(text), duration).show();

                    Looper.loop();
                }
                catch (final Exception ignore)
                {
                    ignore.printStackTrace();
                }
            }
        };
        //设置进程优先级为最高级别，以便尽可能快的显示出Toast信息
        t.setPriority(Thread.MAX_PRIORITY);
        t.start();

        //延迟执行当前代码
        try
        {
            Thread.sleep(duration == Toast.LENGTH_SHORT ? 1500 //
                    : (duration == Toast.LENGTH_LONG ? 3000 : duration));
        }
        catch (final Exception e1)
        {
            e1.printStackTrace();
        }
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWait(final int resId)
    {
        showAndWait(mContext.getText(resId), Toast.LENGTH_SHORT);
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWait(final Object text)
    {
        showAndWait(text, Toast.LENGTH_SHORT);
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWaitLong(final CharSequence text)
    {
        showAndWait(text, Toast.LENGTH_LONG);
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWaitLong(final int resId)
    {
        showAndWait(mContext.getText(resId), Toast.LENGTH_LONG);
    }

    /**
     * {@link #showAndWait(Object, int)}
     */
    public static final void showAndWaitLong(final Object text)
    {
        showAndWait(text, Toast.LENGTH_LONG);
    }

    public static final void showLong(final CharSequence text)
    {
        show(text, Toast.LENGTH_LONG);
    }

    public static final void showLong(final int resId)
    {
        show(mContext.getText(resId), Toast.LENGTH_LONG);
    }

    public static final void showLong(final Object text)
    {
        show(text, Toast.LENGTH_LONG);
    }

    private static class ToastHandler extends Handler
    {
        private static final int MAKE_TOAST = 0;
        private static final int ONE_TOAST = 1;
        private final Toast mToast;

        public ToastHandler(final Toast toast)
        {
            super(Looper.getMainLooper());
            this.mToast = toast;
        }

        @Override
        public void handleMessage(final Message msg)
        {
            switch (msg.what)
            {
                case MAKE_TOAST:
                    if (msg.obj instanceof CharSequence)
                        mMakedToast = Toast.makeText(mContext, (CharSequence) msg.obj, msg.arg1);
                    else
                        mMakedToast = Toast.makeText(mContext, String.valueOf(msg.obj), msg.arg1);
                    mMakedToast.show();
                    break;
                case ONE_TOAST:
                    this.mToast.setDuration(msg.arg1);
                    
                    ViewGroup group = (ViewGroup) mToast.getView();
                    group.setBackgroundColor(Color.WHITE);

                    TextView textView = (TextView) group.getChildAt(0);
                    textView.setTextColor(Color.BLACK);
                    textView.setTextSize(16);

                    if (msg.obj instanceof CharSequence)
                        this.mToast.setText((CharSequence) msg.obj);
                    else
                        this.mToast.setText(String.valueOf(msg.obj));
                    this.mToast.show();
                    break;
            }
        }
    }
}
